#include <SoftwareSerial.h>
#include <stdlib.h>  // 用于 rand() 和 srand()
#include <time.h>    // 用于 time()

const char *deviceName = "CAR1";//名称不能重复

// 定义软件串口用于 4G 模块通信（RX=10, TX=11）
SoftwareSerial moduleSerial(10, 11);

// GPS 数据缓冲区
char gpsBuffer[200]; // 存储 GPS 数据的缓冲区
bool gpsDataReady = false;

// 函数声明
void sendCommand(const char *cmd);
void parseGPSData(const char *data);
void sendMQTTMessage(float latitude, float longitude);
bool tiaoshi = false;

// 初始化
void setup() {
  // 设置串口通信
  if (tiaoshi)
    Serial.begin(9600);        // Arduino 串口调试
  moduleSerial.begin(9600);  // 模块串口通信

  // 等待模块启动
  delay(8000);
  if (tiaoshi)
    Serial.println("初始化模块...");

  // 初始化 GPS 定位
  sendCommand("AT+MGPSC=1\r\n"); // 开启 GPS 功能
  delay(500);
  sendCommand("AT+MGPSGET=0\r\n"); // 暂时关闭 NMEA 数据输出
  delay(500);

  // 设置 4G MQTT 连接
  sendCommand("AT+MDISCONNECT\r\n"); // 断开已有 MQTT 连接
  delay(200);
  sendCommand("AT+MIPCLOSE\r\n");    // 关闭当前会话
  delay(200);
  sendCommand("AT+QICSGP=1,1,\"\",\"\",\"\"\r\n"); // 设置 APN
  delay(200);
  sendCommand("AT+NETOPEN\r\n");     // 打开网络
  delay(3000);

  // 配置 MQTT 连接
  char command[100]; // 假设命令长度不会超过 100 个字符
  srand(time(NULL));  // 初始化随机数种子
  sprintf(command, "AT+MCONFIG=\"%s_%d\",\"\",\"\",0,0,0,\"1883\",\"2024\"\r\n", deviceName,rand()%1000);
  sendCommand(command);
  delay(200);
  sendCommand("AT+MIPSTART=\"替换为你的MQTT Broker地址\",1883,3\r\n"); // 连接 MQTT Broker
  delay(2000);
  sendCommand("AT+MCONNECT=0,60\r\n"); // 连接到 MQTT 服务器
  delay(200);
  sendCommand("AT+MGPSGET=ALL,1\r\n");
  delay(200);

  // 向 gps/lastLocation 发送 online 消息
  char onlineMessage[100];
  snprintf(onlineMessage, sizeof(onlineMessage), "{\"name\":\"%s\",\"msg\":\"online\"}", deviceName);

  char mqttCommand[100];
  snprintf(mqttCommand, sizeof(mqttCommand), "AT+MPUBEX=\"gps/lastLocation\",0,0,%d\r\n", strlen(onlineMessage));

  if (tiaoshi) {
    Serial.print("发送指令: ");
    Serial.println(mqttCommand);
  }
  sendCommand(mqttCommand);       // 发送 MQTT 发布指令
  moduleSerial.print(onlineMessage); // 发送消息内容
  if (tiaoshi) {
    Serial.print("发送 MQTT 消息: ");
    Serial.println(onlineMessage);
  }
}

void loop() {
  static int index = 0;
  while (moduleSerial.available()) {
    char c = moduleSerial.read();

    if (c == '\n') {
      gpsBuffer[index] = '\0';
      index = 0;
      gpsDataReady = true;
    } else if (c != '\r') {
      gpsBuffer[index++] = c;
    }

    if (gpsDataReady) {
      gpsDataReady = false;
      if (strncmp(gpsBuffer, "$GNGLL", 6) == 0) {
        if (tiaoshi)
          Serial.println(gpsBuffer); // 打印完整的 $GNGLL 句子
        parseGPSData(gpsBuffer);
      }
    }
  }
}

// 发送 AT 指令并调试输出
void sendCommand(const char *cmd) {
  moduleSerial.print(cmd);
  if (tiaoshi)
    Serial.print("发送指令: ");
  if (tiaoshi)
    Serial.println(cmd);
  delay(500); // 等待模块响应
  if (tiaoshi)
    while (moduleSerial.available()) {
      Serial.write(moduleSerial.read()); // 打印模块的响应
    }
}

// 转换 GPS 数据中的纬度和经度格式
float convertToDecimalDegrees(float rawValue) {
  int degrees = (int)(rawValue / 100);           // 提取度部分
  float minutes = rawValue - (degrees * 100);    // 提取分部分
  return degrees + (minutes / 60.0);             // 转换为十进制度
}

// 解析 GPS 数据
void parseGPSData(const char *data) {
  char *token;
  char gpsLat[15], gpsLon[15], status;

  token = strtok(data, ",");
  token = strtok(NULL, ","); // Latitude
  strcpy(gpsLat, token);

  token = strtok(NULL, ",");
  token = strtok(NULL, ","); // Longitude
  strcpy(gpsLon, token);

  token = strtok(NULL, ",");
  token = strtok(NULL, ",");
  token = strtok(NULL, ","); // Status
  status = *token;

  if (status == 'A') { // 如果定位有效
    float rawLatitude = atof(gpsLat);            // 原始纬度
    float rawLongitude = atof(gpsLon);          // 原始经度
    float latitude = convertToDecimalDegrees(rawLatitude);  // 转换纬度
    float longitude = convertToDecimalDegrees(rawLongitude); // 转换经度

    // 调试输出
    if (tiaoshi) {
      Serial.print("纬度: ");
      Serial.println(latitude, 6);
      Serial.print("经度: ");
      Serial.println(longitude, 6);
    }
    // 通过 MQTT 发送 GPS 数据
    sendMQTTMessage(latitude, longitude);
  } else {
    if (tiaoshi)
      Serial.println("无效定位");
  }
}

// 发送 MQTT 消息
void sendMQTTMessage(float latitude, float longitude) {
  char latBuffer[15]; // 用于存储纬度的字符串
  char lonBuffer[15]; // 用于存储经度的字符串

  // 转换浮点数为字符串
  dtostrf(latitude, 0, 6, latBuffer); // 6 表示保留 6 位小数
  dtostrf(longitude, 0, 6, lonBuffer);

  char mqttMessage[100]; // 增大缓冲区
  snprintf(mqttMessage, sizeof(mqttMessage), "{\"name\":\"%s\",\"lat\":%s,\"lon\":%s}", deviceName, latBuffer, lonBuffer);

  // 调试打印
  if (tiaoshi) {
    Serial.print("调试: MQTT 消息 = ");
    Serial.println(mqttMessage);
  }
  char mqttCommand[100];
  snprintf(mqttCommand, sizeof(mqttCommand), "AT+MPUBEX=\"gps/location\",0,0,%d\r\n", strlen(mqttMessage));

  // 调试打印
  if (tiaoshi) {
    Serial.print("发送指令: ");
    Serial.println(mqttCommand);
  }
  sendCommand(mqttCommand);       // 发送 MQTT 发布指令
  moduleSerial.print(mqttMessage); // 发送消息内容
  if (tiaoshi) {
    Serial.print("发送 MQTT 消息: ");
    Serial.println(mqttMessage);
  }
}